Add api for image transfer via copy-and-paste (#156408)
authorMatthias Clasen <mclasen@redhat.com>
Sun, 31 Oct 2004 05:40:25 +0000 (05:40 +0000)
committerMatthias Clasen <matthiasc@src.gnome.org>
Sun, 31 Oct 2004 05:40:25 +0000 (05:40 +0000)
2004-10-31  Matthias Clasen  <mclasen@redhat.com>

Add api for image transfer via copy-and-paste (#156408)

* gtk/gtkclipboard.c (gtk_clipboard_set_image)
(gtk_clipboard_request_image, gtk_clipboard_wait_for_image)
(gtk_clipboard_wait_is_image_available): New functions for image
transfer.

* gtk/gtkselection.h:
* gtk/gtkselection.c (gtk_selection_data_targets_include_image):
New function, similar to gtk_selection_data_targets_include_text().

ChangeLog
ChangeLog.pre-2-10
ChangeLog.pre-2-6
ChangeLog.pre-2-8
docs/reference/gtk/gtk-sections.txt
gtk/gtkclipboard.c
gtk/gtkclipboard.h
gtk/gtkselection.c
gtk/gtkselection.h

index 3fb4d9189b5b3ef08b52e53b46f245c8475a1908..4d9f121d30757ee1b98fce6eeac7b8c1315afa69 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,16 @@
 2004-10-31  Matthias Clasen  <mclasen@redhat.com>
 
+       Add api for image transfer via copy-and-paste (#156408)
+       
+       * gtk/gtkclipboard.c (gtk_clipboard_set_image) 
+       (gtk_clipboard_request_image, gtk_clipboard_wait_for_image) 
+       (gtk_clipboard_wait_is_image_available): New functions for image
+       transfer.
+
+       * gtk/gtkselection.h:
+       * gtk/gtkselection.c (gtk_selection_data_targets_include_image): 
+       New function, similar to gtk_selection_data_targets_include_text().
+
        * gtk/gtkprogressbar.[hc]: Add an ellipsize property with 
        getter and setter.  (#156845, Morten Welinder)
 
index 3fb4d9189b5b3ef08b52e53b46f245c8475a1908..4d9f121d30757ee1b98fce6eeac7b8c1315afa69 100644 (file)
@@ -1,5 +1,16 @@
 2004-10-31  Matthias Clasen  <mclasen@redhat.com>
 
+       Add api for image transfer via copy-and-paste (#156408)
+       
+       * gtk/gtkclipboard.c (gtk_clipboard_set_image) 
+       (gtk_clipboard_request_image, gtk_clipboard_wait_for_image) 
+       (gtk_clipboard_wait_is_image_available): New functions for image
+       transfer.
+
+       * gtk/gtkselection.h:
+       * gtk/gtkselection.c (gtk_selection_data_targets_include_image): 
+       New function, similar to gtk_selection_data_targets_include_text().
+
        * gtk/gtkprogressbar.[hc]: Add an ellipsize property with 
        getter and setter.  (#156845, Morten Welinder)
 
index 3fb4d9189b5b3ef08b52e53b46f245c8475a1908..4d9f121d30757ee1b98fce6eeac7b8c1315afa69 100644 (file)
@@ -1,5 +1,16 @@
 2004-10-31  Matthias Clasen  <mclasen@redhat.com>
 
+       Add api for image transfer via copy-and-paste (#156408)
+       
+       * gtk/gtkclipboard.c (gtk_clipboard_set_image) 
+       (gtk_clipboard_request_image, gtk_clipboard_wait_for_image) 
+       (gtk_clipboard_wait_is_image_available): New functions for image
+       transfer.
+
+       * gtk/gtkselection.h:
+       * gtk/gtkselection.c (gtk_selection_data_targets_include_image): 
+       New function, similar to gtk_selection_data_targets_include_text().
+
        * gtk/gtkprogressbar.[hc]: Add an ellipsize property with 
        getter and setter.  (#156845, Morten Welinder)
 
index 3fb4d9189b5b3ef08b52e53b46f245c8475a1908..4d9f121d30757ee1b98fce6eeac7b8c1315afa69 100644 (file)
@@ -1,5 +1,16 @@
 2004-10-31  Matthias Clasen  <mclasen@redhat.com>
 
+       Add api for image transfer via copy-and-paste (#156408)
+       
+       * gtk/gtkclipboard.c (gtk_clipboard_set_image) 
+       (gtk_clipboard_request_image, gtk_clipboard_wait_for_image) 
+       (gtk_clipboard_wait_is_image_available): New functions for image
+       transfer.
+
+       * gtk/gtkselection.h:
+       * gtk/gtkselection.c (gtk_selection_data_targets_include_image): 
+       New function, similar to gtk_selection_data_targets_include_text().
+
        * gtk/gtkprogressbar.[hc]: Add an ellipsize property with 
        getter and setter.  (#156845, Morten Welinder)
 
index b235fdd7ac516b506026b4ee98387ad6bae5e011..7127b856b94a88257b45e48840cc03cb1a9b6584 100644 (file)
@@ -5033,6 +5033,7 @@ gtk_selection_data_get_pixbuf
 gtk_selection_data_set_uris
 gtk_selection_data_get_uris
 gtk_selection_data_get_targets
+gtk_selection_data_targets_include_image
 gtk_selection_data_targets_include_text
 gtk_selection_remove_all
 gtk_selection_clear
@@ -5062,12 +5063,16 @@ gtk_clipboard_set_with_owner
 gtk_clipboard_get_owner
 gtk_clipboard_clear
 gtk_clipboard_set_text
+gtk_clipboard_set_image
 gtk_clipboard_request_contents
 gtk_clipboard_request_text
+gtk_clipboard_request_image
 gtk_clipboard_request_targets
 gtk_clipboard_wait_for_contents
 gtk_clipboard_wait_for_text
+gtk_clipboard_wait_for_image
 gtk_clipboard_wait_is_text_available
+gtk_clipboard_wait_is_image_available
 gtk_clipboard_wait_for_targets
 gtk_clipboard_wait_is_target_available
 gtk_clipboard_set_can_store
index cc78e1f84730b8e67693a12f15197e101c452e2b..6a23db7e836d60b01e189e24e954e10eb6cd6be3 100644 (file)
@@ -46,6 +46,7 @@ typedef struct _GtkClipboardClass GtkClipboardClass;
 
 typedef struct _RequestContentsInfo RequestContentsInfo;
 typedef struct _RequestTextInfo RequestTextInfo;
+typedef struct _RequestImageInfo RequestImageInfo;
 typedef struct _RequestTargetsInfo RequestTargetsInfo;
 
 struct _GtkClipboard 
@@ -95,6 +96,12 @@ struct _RequestTextInfo
   gpointer user_data;
 };
 
+struct _RequestImageInfo
+{
+  GtkClipboardImageReceivedFunc callback;
+  gpointer user_data;
+};
+
 struct _RequestTargetsInfo
 {
   GtkClipboardTargetsReceivedFunc callback;
@@ -702,6 +709,7 @@ text_clear_func (GtkClipboard *clipboard,
   g_free (data);
 }
 
+
 /**
  * gtk_clipboard_set_text:
  * @clipboard: a #GtkClipboard object
@@ -731,15 +739,13 @@ gtk_clipboard_set_text (GtkClipboard *clipboard,
   gtk_target_list_add_text_targets (list, 0);
 
   n_targets = g_list_length (list->list);
-  targets = g_new (GtkTargetEntry, n_targets);
+  targets = g_new0 (GtkTargetEntry, n_targets);
   for (l = list->list, i = 0; l; l = l->next, i++)
     {
       GtkTargetPair *pair = (GtkTargetPair *)l->data;
       targets[i].target = gdk_atom_name (pair->target);
-      targets[i].flags = 0;
-      targets[i].info = 0;
     }
-
+  
   if (len < 0)
     len = strlen (text);
   
@@ -753,6 +759,67 @@ gtk_clipboard_set_text (GtkClipboard *clipboard,
   gtk_target_list_unref (list);
 }
 
+static void 
+pixbuf_get_func (GtkClipboard     *clipboard,
+                GtkSelectionData *selection_data,
+                guint             info,
+                gpointer          data)
+{
+  gtk_selection_data_set_pixbuf (selection_data, data);
+}
+
+static void 
+pixbuf_clear_func (GtkClipboard *clipboard,
+                  gpointer      data)
+{
+  g_object_unref (data);
+}
+
+/**
+ * gtk_clipboard_set_image:
+ * @clipboard: a #GtkClipboard object
+ * @pixbuf:    a #GdkPixbuf 
+ * 
+ * Sets the contents of the clipboard to the given #GdkPixbuf. 
+ * GTK+ will take responsibility for responding for requests 
+ * for the image, and for converting the image into the 
+ * requested format.
+ * 
+ * Since: 2.6
+ **/
+void
+gtk_clipboard_set_image (GtkClipboard *clipboard,
+                         GdkPixbuf    *pixbuf)
+{
+  GtkTargetList *list;
+  GList *l;
+  GtkTargetEntry *targets;
+  gint n_targets, i;
+
+  g_return_if_fail (clipboard != NULL);
+  g_return_if_fail (GDK_IS_PIXBUF (pixbuf));
+
+  list = gtk_target_list_new (NULL, 0);
+  gtk_target_list_add_image_targets (list, 0, TRUE);
+
+  n_targets = g_list_length (list->list);
+  targets = g_new0 (GtkTargetEntry, n_targets);
+  for (l = list->list, i = 0; l; l = l->next, i++)
+    {
+      GtkTargetPair *pair = (GtkTargetPair *)l->data;
+      targets[i].target = gdk_atom_name (pair->target);
+    }
+
+  gtk_clipboard_set_with_data (clipboard, 
+                              targets, n_targets,
+                              pixbuf_get_func, pixbuf_clear_func,
+                              g_object_ref (pixbuf));
+  gtk_clipboard_set_can_store (clipboard, NULL, 0);
+
+  g_free (targets);
+  gtk_target_list_unref (list);
+}
+
 static void
 set_request_contents_info (GtkWidget           *widget,
                           RequestContentsInfo *info)
@@ -909,6 +976,83 @@ gtk_clipboard_request_text (GtkClipboard                *clipboard,
                                  info);
 }
 
+static void 
+request_image_received_func (GtkClipboard     *clipboard,
+                            GtkSelectionData *selection_data,
+                            gpointer          data)
+{
+  RequestImageInfo *info = data;
+  GdkPixbuf *result = NULL;
+
+  result = gtk_selection_data_get_pixbuf (selection_data);
+
+  if (!result)
+    {
+      /* If we asked for image/png and didn't get it, try image/jpeg;
+       * if we asked for image/jpeg and didn't get it, try image/gif;
+       * If we asked for anything else and didn't get it, give up.
+       */
+      if (selection_data->target == gdk_atom_intern ("image/png", FALSE))
+       {
+         gtk_clipboard_request_contents (clipboard,
+                                         gdk_atom_intern ("image/jpeg", FALSE), 
+                                         request_image_received_func, info);
+         return;
+       }
+      else if (selection_data->target == gdk_atom_intern ("image/jpeg", FALSE))
+       {
+         gtk_clipboard_request_contents (clipboard,
+                                         gdk_atom_intern ("image/gif", FALSE), 
+                                         request_text_received_func, info);
+         return;
+       }
+    }
+
+  info->callback (clipboard, result, info->user_data);
+  g_free (info);
+  g_object_unref (result);
+}
+
+/**
+ * gtk_clipboard_request_image:
+ * @clipboard: a #GtkClipboard
+ * @callback:  a function to call when the image is received,
+ *             or the retrieval fails. (It will always be called
+ *             one way or the other.)
+ * @user_data: user data to pass to @callback.
+ * 
+ * Requests the contents of the clipboard as image. When the image is
+ * later received, it will be converted to a #GdkPixbuf, and
+ * @callback will be called. 
+ *
+ * The @pixbuf parameter to @callback will contain the resulting 
+ * #GdkPixbuf if the request succeeded, or %NULL if it failed. This 
+ * could happen for various reasons, in particular if the clipboard 
+ * was empty or if the contents of the clipboard could not be 
+ * converted into an image.
+ *
+ * Since: 2.6
+ **/
+void 
+gtk_clipboard_request_image (GtkClipboard                  *clipboard,
+                            GtkClipboardImageReceivedFunc  callback,
+                            gpointer                       user_data)
+{
+  RequestImageInfo *info;
+  
+  g_return_if_fail (clipboard != NULL);
+  g_return_if_fail (callback != NULL);
+  
+  info = g_new (RequestImageInfo, 1);
+  info->callback = callback;
+  info->user_data = user_data;
+
+  gtk_clipboard_request_contents (clipboard, 
+                                 gdk_atom_intern ("image/png", FALSE),
+                                 request_image_received_func,
+                                 info);
+}
+
 static void 
 request_targets_received_func (GtkClipboard     *clipboard,
                               GtkSelectionData *selection_data,
@@ -1042,7 +1186,6 @@ clipboard_text_received_func (GtkClipboard *clipboard,
   g_main_loop_quit (results->loop);
 }
 
-
 /**
  * gtk_clipboard_wait_for_text:
  * @clipboard: a #GtkClipboard
@@ -1064,7 +1207,6 @@ gtk_clipboard_wait_for_text (GtkClipboard *clipboard)
 {
   WaitResults results;
 
-  g_return_val_if_fail (clipboard != NULL, NULL);
   g_return_val_if_fail (clipboard != NULL, NULL);
   
   results.data = NULL;
@@ -1085,6 +1227,62 @@ gtk_clipboard_wait_for_text (GtkClipboard *clipboard)
 
   return results.data;
 }
+
+static void 
+clipboard_image_received_func (GtkClipboard *clipboard,
+                              GdkPixbuf    *pixbuf,
+                              gpointer      data)
+{
+  WaitResults *results = data;
+
+  results->data = g_object_ref (pixbuf);
+  g_main_loop_quit (results->loop);
+}
+
+/**
+ * gtk_clipboard_wait_for_image:
+ * @clipboard: a #GtkClipboard
+ * 
+ * Requests the contents of the clipboard as image and converts
+ * the result to a #GdkPixbuf. This function waits for
+ * the data to be received using the main loop, so events,
+ * timeouts, etc, may be dispatched during the wait.
+ * 
+ * Return value: a newly-allocated #GdkPixbuf object which must
+ *               be disposed with g_object_unref(), or %NULL if 
+ *               retrieving the selection data failed. (This 
+ *               could happen for various reasons, in particular 
+ *               if the clipboard was empty or if the contents of 
+ *               the clipboard could not be converted into an image.)
+ *
+ * Since: 2.6
+ **/
+GdkPixbuf *
+gtk_clipboard_wait_for_image (GtkClipboard *clipboard)
+{
+  WaitResults results;
+
+  g_return_val_if_fail (clipboard != NULL, NULL);
+  
+  results.data = NULL;
+  results.loop = g_main_loop_new (NULL, TRUE);
+
+  gtk_clipboard_request_image (clipboard,
+                              clipboard_image_received_func,
+                              &results);
+
+  if (g_main_loop_is_running (results.loop))
+    {
+      GDK_THREADS_LEAVE ();
+      g_main_loop_run (results.loop);
+      GDK_THREADS_ENTER ();
+    }
+
+  g_main_loop_unref (results.loop);
+
+  return results.data;
+}
+
 /**
  * gtk_clipboard_get_display:
  * @clipboard: a #GtkClipboard
@@ -1109,10 +1307,9 @@ gtk_clipboard_get_display (GtkClipboard *clipboard)
  * 
  * Test to see if there is text available to be pasted
  * This is done by requesting the TARGETS atom and checking
- * if it contains any of the names: STRING, TEXT, COMPOUND_TEXT,
- * UTF8_STRING. This function waits for the data to be received
- * using the main loop, so events, timeouts, etc, may be dispatched
- * during the wait.
+ * if it contains any of the supported text targets. This function 
+ * waits for the data to be received using the main loop, so events, 
+ * timeouts, etc, may be dispatched during the wait.
  *
  * This function is a little faster than calling
  * gtk_clipboard_wait_for_text() since it doesn't need to retrieve
@@ -1136,6 +1333,41 @@ gtk_clipboard_wait_is_text_available (GtkClipboard *clipboard)
   return result;
 }
 
+/**
+ * gtk_clipboard_wait_is_image_available:
+ * @clipboard: a #GtkClipboard
+ * 
+ * Test to see if there is an image available to be pasted
+ * This is done by requesting the TARGETS atom and checking
+ * if it contains any of the supported image targets. This function 
+ * waits for the data to be received using the main loop, so events, 
+ * timeouts, etc, may be dispatched during the wait.
+ *
+ * This function is a little faster than calling
+ * gtk_clipboard_wait_for_image() since it doesn't need to retrieve
+ * the actual image data.
+ * 
+ * Return value: %TRUE is there is an image available, %FALSE otherwise.
+ *
+ * Since: 2.6
+ **/
+gboolean
+gtk_clipboard_wait_is_image_available (GtkClipboard *clipboard)
+{
+  GtkSelectionData *data;
+  gboolean result = FALSE;
+
+  data = gtk_clipboard_wait_for_contents (clipboard, 
+                                         gdk_atom_intern ("TARGETS", FALSE));
+  if (data)
+    {
+      result = gtk_selection_data_targets_include_image (data, FALSE);
+      gtk_selection_data_free (data);
+    }
+
+  return result;
+}
+
 /**
  * gtk_clipboard_wait_for_targets
  * @clipboard: a #GtkClipboard
index c05e63cc4f3b77339006f99b3fc523f696e54293..319c38aca64e5309f4d723baeb68d319526531ae 100644 (file)
@@ -38,6 +38,9 @@ typedef void (* GtkClipboardReceivedFunc)        (GtkClipboard     *clipboard,
 typedef void (* GtkClipboardTextReceivedFunc)    (GtkClipboard     *clipboard,
                                                  const gchar      *text,
                                                  gpointer          data);
+typedef void (* GtkClipboardImageReceivedFunc)   (GtkClipboard     *clipboard,
+                                                 GdkPixbuf        *pixbuf,
+                                                 gpointer          data);
 typedef void (* GtkClipboardTargetsReceivedFunc) (GtkClipboard     *clipboard,
                                                  GdkAtom          *atoms,
                                                  gint              n_atoms,
@@ -82,6 +85,8 @@ void     gtk_clipboard_clear          (GtkClipboard          *clipboard);
 void     gtk_clipboard_set_text       (GtkClipboard          *clipboard,
                                       const gchar           *text,
                                       gint                   len);
+void     gtk_clipboard_set_image      (GtkClipboard          *clipboard,
+                                      GdkPixbuf             *pixbuf);
 
 void gtk_clipboard_request_contents (GtkClipboard                    *clipboard,
                                     GdkAtom                          target,
@@ -90,6 +95,9 @@ void gtk_clipboard_request_contents (GtkClipboard                    *clipboard,
 void gtk_clipboard_request_text     (GtkClipboard                    *clipboard,
                                     GtkClipboardTextReceivedFunc     callback,
                                     gpointer                         user_data);
+void gtk_clipboard_request_image    (GtkClipboard                    *clipboard,
+                                    GtkClipboardImageReceivedFunc    callback,
+                                    gpointer                         user_data);
 void gtk_clipboard_request_targets  (GtkClipboard                    *clipboard,
                                     GtkClipboardTargetsReceivedFunc  callback,
                                     gpointer                         user_data);
@@ -97,11 +105,13 @@ void gtk_clipboard_request_targets  (GtkClipboard                    *clipboard,
 GtkSelectionData *gtk_clipboard_wait_for_contents (GtkClipboard  *clipboard,
                                                   GdkAtom        target);
 gchar *           gtk_clipboard_wait_for_text     (GtkClipboard  *clipboard);
+GdkPixbuf *       gtk_clipboard_wait_for_image    (GtkClipboard  *clipboard);
 gboolean          gtk_clipboard_wait_for_targets  (GtkClipboard  *clipboard,
                                                   GdkAtom      **targets,
                                                   gint          *n_targets);
 
 gboolean gtk_clipboard_wait_is_text_available   (GtkClipboard *clipboard);
+gboolean gtk_clipboard_wait_is_image_available  (GtkClipboard *clipboard);
 gboolean gtk_clipboard_wait_is_target_available (GtkClipboard *clipboard,
                                                 GdkAtom       target);
 
index ac8836975bf27a0b7b9311480096f5f5a43b1d25..ab60873811075b05ec4c18738f0fff3adc117187 100644 (file)
@@ -1496,7 +1496,10 @@ gtk_selection_data_targets_include_text (GtkSelectionData *selection_data)
              targets[i] == text_plain_atom ||
              targets[i] == text_plain_utf8_atom ||
              targets[i] == text_plain_locale_atom)
-           result = TRUE;
+           {
+             result = TRUE;
+             break;
+           }
        }
 
       g_free (targets);
@@ -1504,6 +1507,54 @@ gtk_selection_data_targets_include_text (GtkSelectionData *selection_data)
 
   return result;
 }
+
+/**
+ * gtk_selection_data_targets_include_image:
+ * @selection_data: a #GtkSelectionData object
+ * @writable: whether to accept only targets for which GTK+ knows
+ *   how to convert a pixbuf into the format
+ * 
+ * Given a #GtkSelectionData object holding a list of targets,
+ * determines if any of the targets in @targets can be used to
+ * provide a #GdkPixbuf.
+ * 
+ * Return value: %TRUE if @selection_data holds a list of targets,
+ *   and a suitable target for images is included, otherwise %FALSE.
+ *
+ * Since: 2.6
+ **/
+gboolean 
+gtk_selection_data_targets_include_image (GtkSelectionData *selection_data,
+                                         gboolean          writable)
+{
+  GdkAtom *targets;
+  gint n_targets;
+  gint i;
+  gboolean result = FALSE;
+  GtkTargetList *list;
+  GList *l;
+
+  init_atoms ();
+
+  if (gtk_selection_data_get_targets (selection_data, &targets, &n_targets))
+    {
+      list = gtk_target_list_new (NULL, 0);
+      gtk_target_list_add_image_targets (list, 0, writable);
+      for (i=0; i < n_targets && !result; i++)
+       {
+         for (l = list->list; l && !result; l = l->next)
+           {
+             GtkTargetPair *pair = (GtkTargetPair *)l->data;
+             if (pair->target == targets[i])
+               result = TRUE;
+           }
+       }
+      gtk_target_list_unref (list);
+      g_free (targets);
+    }
+
+  return result;
+}
          
 /*************************************************************
  * gtk_selection_init:
index 5623b440e477bb1067fcd81fe62ba1ab49f11a64..f3df99e10b5fe5d750aaad7a2fbe2c46bcb9e221 100644 (file)
@@ -144,9 +144,9 @@ gboolean gtk_selection_data_set_text (GtkSelectionData     *selection_data,
                                      const gchar          *str,
                                      gint                  len);
 guchar * gtk_selection_data_get_text (GtkSelectionData     *selection_data);
-gboolean gtk_selection_data_set_pixbuf (GtkSelectionData   *selection_data,
-                                       GdkPixbuf          *pixbuf);
-GdkPixbuf *gtk_selection_data_get_pixbuf (GtkSelectionData *selection_data);
+gboolean gtk_selection_data_set_pixbuf   (GtkSelectionData  *selection_data,
+                                         GdkPixbuf         *pixbuf);
+GdkPixbuf *gtk_selection_data_get_pixbuf (GtkSelectionData  *selection_data);
 gboolean gtk_selection_data_set_uris (GtkSelectionData     *selection_data,
                                      gchar               **uris);
 gchar  **gtk_selection_data_get_uris (GtkSelectionData     *selection_data);
@@ -155,6 +155,8 @@ gboolean gtk_selection_data_get_targets          (GtkSelectionData  *selection_d
                                                  GdkAtom          **targets,
                                                  gint              *n_atoms);
 gboolean gtk_selection_data_targets_include_text (GtkSelectionData  *selection_data);
+gboolean gtk_selection_data_targets_include_image (GtkSelectionData  *selection_data,
+                                                  gboolean           writable);
 
 /* Called when a widget is destroyed */